package com.codeoss.framework.webide.app.service.impl;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.db.service.IDDLService;
import com.codeoss.framework.db.service.impl.IDDLServiceStore;
import com.codeoss.framework.impexp.ExportManager;
import com.codeoss.framework.util.DBUtil;
import com.codeoss.framework.webide.app.service.CommonAppDataHandler;
import com.codeoss.framework.webide.service.IModelFormPageService;
import com.codeoss.module.ir.model.IrApplication;
import com.codeoss.module.ir.model.IrModel;
import com.codeoss.module.ir.service.IIrModelService;

@Service("ir_modelAppDataHandler")
public class IrModelAppDataHandler extends CommonAppDataHandler {
    @Autowired
    private IIrModelService irModelService;
    @Autowired
    private ExportManager exportManager;
    @Autowired
    private ITableStore tableStore;
    @Autowired
	private IModelFormPageService modelFormPageService;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private IDDLServiceStore ddlServiceStore;
    @Value("${framework.db-type}")
	private String dbType;
    @Autowired
	private DBUtil dbUtil;
	@Override
	public void dataExport(YunContext yunContext, IrApplication irApplication, String tableName) throws IOException{
		// TODO Auto-generated method stub
		QueryWrapper<IrModel> queryWrapper=new QueryWrapper<IrModel>();
		queryWrapper.in("module_type", getModuleTypeList(yunContext, irApplication));
		queryWrapper.orderByAsc("id");
		List<IrModel> irModelList=irModelService.list(queryWrapper);
		for (int i = 0; i < irModelList.size(); i++) {
			IrModel irModel=irModelList.get(i);
			Table table=tableStore.get("ir_model");
			Query query=new Query();
			query.add(Restrictions.eq("table_name", irModel.getTableName()));
			String filename="ir_model"+i;
			writeConfigKeyValue(yunContext, "ir_model", filename);
			FileOutputStream os=createFileOutputStream(yunContext, filename);
			exportManager.exportProperties(yunContext, table, query, os);
			os.close();
		}
	}

	@Override
	@Transactional
	public void dataImport(YunContext yunContext, IrApplication irApplication, String tableName, List<String> filenameList)throws IOException {
		// TODO Auto-generated method stub
		if(filenameList==null) {
			return;
		}
		List<String> tableList=new ArrayList<String>();
		
		for(int i=0;i<filenameList.size();i++) {
			String filename=filenameList.get(i);
			InputStream is=createFileInputStream(yunContext, filename);
			Properties p = new Properties();
			p.load(is);
            is.close();
            
            String ttableName=p.getProperty("table_name");
            String name=p.getProperty("name");
            String description=p.getProperty("description");
            String jsonContent=p.getProperty("json_content");
            String moduleType=p.getProperty("module_type");
            String modelType=p.getProperty("model_type");
            
            IrModel irModel=irModelService.getIrModelByTableName(ttableName);
            if(irModel==null) {
            	irModel=new IrModel();
            }
            irModel.setTableName(ttableName);
            irModel.setName(name);
            irModel.setDescription(description);
            irModel.setJsonContent(jsonContent);
            irModel.setModuleType(moduleType);
            irModel.setModelType(modelType);
            if(irModel.getId()==null) {
            	irModelService.insert(irModel);
            }else {
            	irModelService.update(irModel);
            }
            tableList.add(ttableName);
		}
		for(int i=0;i<tableList.size();i++) {
			String table=tableList.get(i);
			modelFormPageService.syncTable(table,false);
		}
		
	
		Connection connection = DataSourceUtils.getConnection(dataSource);
		try{
			IDDLService ddlService=ddlServiceStore.getDDLService();
			
			Map<Table,List<Column>> columnMap=yunContext.getAttribute("__columnMap__");
			Iterator<Map.Entry<Table,List<Column>>> it=columnMap.entrySet().iterator();
			while(it.hasNext()) {
				Map.Entry<Table,List<Column>> entry=it.next();
				Table table=entry.getKey();
				if(!table.isAuto()) {
					continue;
				}
				if(table.isView()) {
					continue;
				}
				List<Column> columnList=entry.getValue();
				
				for(int i=0;i<columnList.size();i++) {
					Column column = (Column) columnList.get(i);
					if(column.isUnique()) {
						ddlService.createUniqueIndex(connection, table, column);
					}else if(column.getLookupInfo()!=null && column.getLookupInfo().getDataSourceConfig()!=null) {
						ddlService.createForeignKey(connection, table, column);
					}
				}
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally {
			DataSourceUtils.releaseConnection(connection, dataSource);
		}
		addMissingIndex(tableList);
	}
	
	private void addMissingIndex(List<String> tableList) {
		IDDLService ddlService=ddlServiceStore.getDDLService();
		Connection connection = DataSourceUtils.getConnection(dataSource);
		try{
			DatabaseMetaData dbMetaData=connection.getMetaData();
			for(int i=0;i<tableList.size();i++) {
				String tableName=tableList.get(i);
				Table dataTable=tableStore.get(tableName);
				if(!dataTable.isAuto()) {
					continue;
				}
				if(dataTable.isView()) {
					continue;
				}
				Map<String,Object> indexMap=new HashMap<String,Object>();
				String tableName2=tableName;
				if(dbType.equals("oracle")) {
					tableName2=tableName.toUpperCase();
				}
				ResultSet rs=dbMetaData.getIndexInfo(null, null, tableName2, false,true);
				while(rs.next()) {
					String tName=rs.getString("TABLE_NAME");
					String cName=rs.getString("COLUMN_NAME");
					if(tName!=null) {
						tName=tName.toLowerCase();
					}
					if(cName!=null) {
						cName=cName.toLowerCase();
					}
					indexMap.put(tName+"::"+cName,"");
				}
				dbUtil.closeResultSet(rs);
				rs=dbMetaData.getImportedKeys(null, null, tableName2);
				while (rs.next()) {
					String tName=rs.getString("FKTABLE_NAME");
					String cName=rs.getString("FKCOLUMN_NAME");
					if(tName!=null) {
						tName=tName.toLowerCase();
					}
					if(cName!=null) {
						cName=cName.toLowerCase();
					}
					indexMap.put(tName+"::"+cName,"");
				}
				dbUtil.closeResultSet(rs);
				Table table=tableStore.get(tableName);
				List<Column> columnList=table.getAllColumnList();
				for(int j=0;j<columnList.size();j++) {
					Column column=columnList.get(j);
					if(column.isUnique()) {
						if(indexMap.get(tableName+"::"+column.getColumnName())!=null) {
							continue;
						}
						ddlService.createUniqueIndex(connection, table, column);
					}else if(column.getLookupInfo()!=null && column.getLookupInfo().getDataSourceConfig()!=null) {
						if(indexMap.get(tableName+"::"+column.getColumnName())!=null) {
							continue;
						}
						ddlService.createForeignKey(connection, table, column);
					}
				}
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally {
			DataSourceUtils.releaseConnection(connection, dataSource);
		}
	}

}
